package com.ryan.plugin;

import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.ryan.plugin.store.Store;

import java.util.List;

/**
 * 用于遍历所有包含override注解的方法声明及import语句的访问者.
 * 遍历带override的方法声明: 首先查找声明该方法的类, 遍历该类的所有祖先, 包括继承、实现、继承的继承等, 并且找到被override的祖先类.
 * 遍历import语句: 如果store中以及记载了该类则忽略, 没有就记录到store中去.
 */
public class Visitor extends VoidVisitorAdapter<Store> {

    private final ResolvedReferenceTypeDeclaration parent;

    public Visitor(ResolvedReferenceTypeDeclaration parent) {
        this.parent = parent;
    }

    @Override
    public void visit(MethodDeclaration md, Store store) {
        super.visit(md, store);

        md.getAnnotations().forEach(annotationExpr -> {
            if (annotationExpr.getNameAsString().equals("Override")) {
                try {
                    ResolvedMethodLikeDeclaration declaration = md.resolve();
                    ResolvedReferenceTypeDeclaration declaringType = declaration.declaringType();

                    // 遍历所有祖先
                    List<ResolvedReferenceType> ancestors = declaringType.getAllAncestors();
                    for (ResolvedReferenceType ancestor : ancestors) {
                        if (ancestor.getTypeDeclaration().isEmpty()) continue;
                        ResolvedReferenceTypeDeclaration d = ancestor.getTypeDeclaration().get();
                        boolean res = d.getDeclaredMethods().stream().anyMatch(r -> {
                            // 寻找祖先类中是否包含该方法的定义
                            if (declaration.getSignature().equals(r.getSignature())) {
                                store.put(r.getPackageName(), r.getClassName(), r.getSignature(), "override");
                                return true;
                            }
                            return false;
                        });
                        if (res) {
                            break;
                        }
                    }
                } catch (Exception e) {
                    System.err.println("Visitor: " + md.getNameAsString());
                    store.putException(parent.getPackageName(), parent.getClassName(), md.getSignature().asString());
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void visit(ImportDeclaration id, Store store) {
        super.visit(id, store);
        store.put(id.getNameAsString());
    }

    @Override
    public void visit(PackageDeclaration id, Store store) {
        super.visit(id, store);
//        System.out.println(id.getNameAsString());
        store.putPackage(id.getNameAsString());
    }
}
